#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <semaphore.h>
#include <signal.h>
#include <sys/types.h>
#include <pthread.h>
#define NUM_CUSTOMERS 30
#define ROOM_CAPACITY 10


sem_t cust_room,barber;
pthread_key_t   tIsKey;


static sigset_t   signal_mask;


#define NUM_THREADS     50
pthread_t threads[NUM_THREADS];
#define ROOMCAPACITY     10


//Semaphores...
sem_t BarberChairSem;
sem_t RoomSem;



int waiting_chair_seats = 0;
int customersInRoom = 0;

int customerCount = 20;




void *barber_thread(void *arg)
{
	   long tid;
	   tid = (long)arg;

	   sleep(2);

	   printf("------------------------------------------\n[Barber]: opens the shop\n------------------------------------------\n");
	   kill(getpid(),SIGINT);
	  // raise(SIGINT);


	   while(customerCount>0)
	   {
		   kill(getpid(),SIGINT);

		   printf("[Barber]: Customers Remaining = [%d]\n",customerCount);
		   printf("[Barber]: customer_in_room = %d\n",customersInRoom);
		   printf("[barber] : Anyone wants hair cut?\n");
		   sem_post(&RoomSem);
		   sem_post(&BarberChairSem);
		   sleep(1);
	   }

	   printf("[Barber]: No one? okay i will close this shop\n------------------------------------------\n");


}


void *customer_thread(void *arg)
 {

    long tid;
	   tid = (long)arg;
	    int       sig_caught;    /* signal caught       */
	    int       rc;            /* returned code       */
	    pthread_t     me = pthread_self();

	    void *id;
	    id = malloc(sizeof(tid));
	    memcpy(id, &tid, sizeof(tid));

	    //pthread_key_create(&tIsKey, NULL );
	    pthread_setspecific(tIsKey, tid);


	   printf("[customer - %ld] : Standing outside Barber Shop.\n", tid);
	   rc = sigwait (&signal_mask, &sig_caught);
	       if (rc != 0) {
	           printf("Error waiting for Signal\n");
	       }

	       printf("[customer - %ld] : Door opened for me Barber Shop.\n", tid);

	   sem_wait(&RoomSem);
	   customersInRoom++;
	   printf("[customer - %ld] : waiting for barber chair.\n", tid);

	   sem_wait(&BarberChairSem);


	   printf("[customer - %ld] : I am getting hair cut.\n", tid);

	   customerCount --;
	   customersInRoom--;
	   printf("[Customer - %ld ] Leaves Barber shop.\n------------------------------------------\n",tid);

 }


void handler()
{

	  void                 *t;
	  t = pthread_getspecific(tIsKey);
	  int *p;
	  memcpy(p,t,sizeof(p));
	  printf("Attempting to print the id\n");

	  printf(" In Handler - %c\n",	 *p);



}


int main()
{


		int i,rc;
		long t=0; void *status;
		struct sigaction new_action;

		pthread_attr_t attr;
		/* Initialize and set thread detached attribute */
	   pthread_attr_init(&attr);
	   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

	   sem_init(&BarberChairSem, 0, 0);
	   sem_init(&RoomSem,0,ROOMCAPACITY-1);


	   new_action.sa_sigaction =handler;
	   sigaction (SIGINT, &new_action, NULL);


	   //sigaction(int sig, const struct sigaction *restrict act, struct sigaction *restrict oact);

	   /*
	    *       int sem_init(sem_t *sem, int pshared, unsigned int value);
	    *
	    *      sem points to a semaphore object to initialize
	    *
	    * 		pshared is a flag indicating whether or not the semaphore should be shared with fork()ed processes.
	    * 		LinuxThreads does not currently support shared semaphores
	    *
	    * 		value is an initial value to set the semaphore to
	    *
	    */


	   for(i=1;i<=20;i++)
	   {
		 t=i;
	      rc = pthread_create(&threads[i], &attr, customer_thread, (void *)t);
	      if (rc){
	         printf("ERROR; return code from pthread_create() is %d\n", rc);
	         exit(-1);
	      }
	   }

	    sigemptyset (&signal_mask);
	    sigaddset (&signal_mask, SIGINT);
	    rc = pthread_sigmask (SIG_BLOCK, &signal_mask, NULL);
	        if (rc != 0) {
	           printf("Error masking signals for barber!\n");
	        }


	   rc = pthread_create(&threads[0], &attr, barber_thread, (void *)t);
	   	      if (rc){
	   	         printf("ERROR; return code from pthread_create() is %d\n", rc);
	   	         exit(-1);
	   	      }


	      rc = pthread_join(threads[0], &status);
		      if (rc) {
		         printf("ERROR; return code from pthread_join() is %d\n", rc);
		         exit(-1);
	         }

}


/*
 *
 *
 int pthread_sigmask (int how, const sigset_t *restrict set, sigset_t *restrict oset);
 int sigprocmask (int how, const sigset_t *restrict set, sigset_t *restrict oset);



 *
 */

